package york.Game;


import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JPanel;

import york.Game.Unit.SmartUnit;

@SuppressWarnings("serial")
public class Game extends JPanel implements KeyListener, MouseListener, MouseMotionListener{
	boolean Update;
	SmartUnit Focus;
	String GameTime;
	Vector<SmartUnit> AllUnits = new Vector<SmartUnit>();
	Graphics G;
	static int X;
	int Y;
	final static int ScreenSize = 512;
	boolean Running;
	AIManager MyManager;
	
	public Game() {
		X = Y = 0;
		Update = false;
		Focus = null;
		addKeyListener(this);
		addMouseListener(this);
		addMouseMotionListener(this);
		GameTime = "0";
		Running = true;
	}
	
	public void SetManager(AIManager a_AIM) {
		MyManager = a_AIM;
	}
	
	public static void main(String[] args) {
		Game MyGame = new Game();
		AIManager AIM = new AIManager();
		MyGame.SetManager(AIM);
		JFrame jf = new JFrame("Balls of AI");
		jf.add(MyGame);
		jf.addKeyListener(MyGame);
		jf.addMouseListener(MyGame);
		jf.addMouseMotionListener(MyGame);
		jf.setSize(ScreenSize , ScreenSize);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setVisible(true);
		
		MyGame.Setup(AIM);
		MyGame.Running(AIM);
	}
	
	/** <b>Setup()</b><br>
	 * @param AIManager <br>
	 * 
	 * This function adds 5 predators to the game and adds them to  a SmartUnit Group. 
	 * The AIManager only needs the group to be able to update all of them. After the 
	 * predators are added to the group a single prety unit is added. The predators
	 * starting location is a circular formation at the center of the screen. The prey starts
	 * at the top of the screen. 
	 */
	public void Setup(AIManager a_AIM) {
		// -- Temporary code
		// Adds a single unit slightly inside the window boundary for testing
		AllUnits.add(new SmartUnit());
		AllUnits.get(0).setPosition(new Vector2D(100,100));
		AllUnits.add(new SmartUnit());
		AllUnits.get(1).setPosition(new Vector2D(200,200));
		
		a_AIM.AddUnit(AllUnits.get(0));
		a_AIM.AddUnit(AllUnits.get(1));
	}
	
	/** Running(AIManager a_AIM);
	 * Uses a clock to throttle the AI
	 * A clock cycle is 1/10 of a second or 100 milliseconds
	 * This keeps the update fast and slows the AI done so that it doesn't go out
	 * of control
	 */
	public void Running(AIManager a_AIM) {
		//Creates a clock object that waits 1/10 of a second before it tells the game to update again
		Clock CurTime = new Clock((long)100);
		
		if(a_AIM == null)Running = false;
		
		//A boolean is used so an arbitrary break can be triggered if needed
		while(Running){
			//Update the time
			CurTime.update();
			
			//Save the total time to be printed out
			GameTime = Long.toString(CurTime.GetTotalTime()/1000);
			
			//If the timer has triggered a tick
			// Update all the AI units
			if(CurTime.TimeToUpdate()){
				a_AIM.update(CurTime.getInterval());
				CurTime.Updated();
			}
			
			//Updates all units based on their current states
			UpdateUnits(CurTime.getLastTimeLapse());
			
			//Repaint after update
			repaint();
			
			//Slow the processor down slightly to avoid killing the computer
			try {Thread.sleep(5);}
			catch (Exception e) {e.printStackTrace();}
		}
	}
	
	private void UpdateUnits(double d) {
		for(int i = AllUnits.size()-1;i >= 0;i--) {
			((SmartUnit) AllUnits.get(i)).Update(d);
		}
	}

	public void paintComponent(Graphics G) {
		super.paintComponent(G);
		SmartUnit ToDraw;
		for(int i = AllUnits.size()-1;i >= 0;i--) {
			ToDraw = (SmartUnit) AllUnits.get(i);
			ToDraw.Paint(G);
		}
		
		/*
		 * This prints the total game time to the screen
		 * 10 is the height of 1 character
		 * 16 is the distance needed to keep the first number in the frame
		 * 7 is the width of a character
		 */
		G.drawString("Total Time in Seconds", ScreenSize - 20 * 7, 10);
		G.drawString(GameTime, ScreenSize - GameTime.length() * 7 - 16, 20);
	}
	
	//TODO - Finish defining user inputs
	public void keyPressed(KeyEvent e) {
		//Focus.ReceiveCommands((Object)e,Command_Types.KEYPRESSED);
	}
	
	public void keyReleased(KeyEvent e) {
		//Focus.ReceiveCommands((Object)e,Command_Types.KEYRELEASED);
	}

	public void keyTyped(KeyEvent e) {
		//Focus.ReceiveCommands((Object)e,Command_Types.KEYTYPED);
	}

	public void mouseDragged(MouseEvent e) {
		
		//Focus.ReceiveCommands((Object)e,Command_Types.MOUSEDRAGGED);
	}

	public void mouseMoved(MouseEvent e) {
		//Focus.ReceiveCommands((Object)e,Command_Types.MOUSEMOVED);
	}

	public void mouseClicked(MouseEvent e) {
		//Focus.ReceiveCommands((Object)e,Command_Types.MOUSECLICKED);	
	}

	public void mouseEntered(MouseEvent e) {}

	public void mouseExited(MouseEvent e) {}

	public void mousePressed(MouseEvent e) {
		if(e.getButton() == MouseEvent.BUTTON1) {
			boolean Found = false;
			for(int i = AllUnits.size()-1;!Found && i >= 0;i--) {
				if(AllUnits.get(i).Within(new Vector2D(e.getPoint()))) {
					Focus = AllUnits.get(i);
					Focus.MakePriority(true);
					Found = true;
				}
			}
			if(!Found && Focus != null) {
				Focus.MakePriority(false);
				Focus = null;
			}
		}
		else if(e.getButton() == MouseEvent.BUTTON3) {
			if(Focus != null)
				Focus.setDest(e.getPoint());//Sets the position for the focus to move towards
		}
		repaint();
		//Focus.ReceiveCommands((Object)e,Command_Types.MOUSEPRESSED);
	}

	public void mouseReleased(MouseEvent e) {
		//Focus.ReceiveCommands((Object)e,Command_Types.MOUSERELEASED);
	}
	
}
